package cn.edu.dgut.css.sai.jpa.springdatajpaspecifications.repository;

import cn.edu.dgut.css.sai.jpa.springdatajpaspecifications.model.Employee;
import cn.edu.dgut.css.sai.jpa.springdatajpaspecifications.model.Employee_;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;

/**
 * 原生使用Spring Data JPA Criteria API进行复杂查询（完全面向对象，不需要SQL语句）。
 *
 * <p>Spring Data Jpa 支持Criteria的动态查询，并让我们的编码简化，减少模板代码：我们只需要编写好条件 Predicate，其它工作都交给Spring Data Jpa完成。</p>
 *
 * @author sai
 * @see SimpleJpaRepository
 * @since 2020-12-13
 */
@RequiredArgsConstructor
public class EmployeeCustomRepositoryImpl implements EmployeeCustomRepository {

    private final EntityManager entityManager;

    // 可以这么理解，动态复杂查询的过程: 通过编程的方式调用Criteria API动态构建 HQL 语句的过程。
    @Override
    public List<Employee> findByFirstNameAndDepartment(String firstname, String department) {

        // CriteriaBuilder 用于创建查询条件。
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();

        // CriteriaQuery 用于创建整条查询语句（HQL）
        CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);

        // 设置 from 子句，注意 返回值是 Root<?> 类型。
        Root<Employee> employee = cq.from(Employee.class);

        // 使用 CriteriaBuilder 创建条件对象Predicate
        Predicate firstNamePredicate = cb.equal(employee.get(Employee_.firstname), firstname);
        // 创建第二个条件对象Predicate
        Predicate departmentPredicate = cb.equal(employee.get(Employee_.department), department);
        // 把两个条件整合，并赋于到where子句后面。
        cq.where(firstNamePredicate, departmentPredicate);

        // 设置 select 子句
        cq.select(employee);

        // 构建完HQL语句后，调用 EntityManager.createQuery 执行语句，并返回结果集。
        TypedQuery<Employee> query = entityManager.createQuery(cq);

        return query.getResultList();
    }
}
